package psd;

import java.io.*;
import java.util.*;
import java.text.*;



public class RegParser2 {

	


	static public void main(String [] args) {

		RegParser2 parser = new RegParser2();
		parser.parse(args);

		Matcher m = new Matcher( args );
		m.match( parser.folks );
	}

	ArrayList<RegRecord> folks = new ArrayList<RegRecord>();
	File matrixFile = null;




	String matrixFileName = "matrix.csv";

	int N; // number of folks
	//int[][] m; // matrix of dating ability
	private boolean filename_id_flag;


	private void appendID(File file, RegRecord rec) {
		try {
	        BufferedWriter out = new BufferedWriter(new FileWriter(file, true));
	        out.write("\nID: " + rec.id() );
	        out.close();
	       
	    } catch (IOException e) {
	    	e.printStackTrace();
	    
	    }
	}

	


	public void parse(String [] args) {

		if (args == null || args.length == 0 ) {
			printUsage();
			return;
		}

		ArrayList<String> stringDirs = new ArrayList<String>();

		for (int i = 0; i < args.length; i++) {
			String arg = args[i];

			if (arg == null) continue;

			if (arg.startsWith("-he" ) || arg.startsWith("-no") || arg.startsWith( "-re" )
					|| arg.startsWith("-out") || arg.startsWith("-mat") ) {
				continue; 
			}
			
			if (arg.startsWith( "-fi") ) {
				filename_id_flag = true;
				continue;
			}

			// otherwise, it is just a file or directory name
			stringDirs.add(args[i]);
		}

		
		for (int i = 0; i < stringDirs.size(); i++) {
			String dir = stringDirs.get(i);
			File dirFile = new File(dir);
			if (!dirFile.exists())
				System.err.println("File or directory does not exist: " + dir);
			else {
				try {
					System.out.println( "Processing " + dirFile.getCanonicalPath() + "\n" );
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				parseDir(dirFile);
			}
		}
	} 

	
	Boolean parseBoolean(String boolString) {
		if (boolString.equals("yes") || boolString.equals("true") || boolString.equals("1"))
			return Boolean.TRUE;
		else if (boolString.equals("no") || boolString.equals("false") || boolString.equals("0"))
			return Boolean.FALSE;
		else return null;
	}

	void parseDir (File directory) {

		if (!directory.exists()) return;

		if (directory.isFile())
			parseFile(directory);
		else {

			File [] fileChildren = directory.listFiles();
			if (fileChildren != null)
				for (int i = 0; i < fileChildren.length; i++) {
					parseDir(fileChildren[i]);
					
				}
		}
	}

	void parseFile (File file) {

		if (!file.exists() || !file.isFile()) return;

		if (!file.getName().endsWith(".txt")) {
			System.err.println("Skipping file because it does not have .txt extension: " + file.getName());
			return;
		}

		// read into String
		String fileString = null;
		InputStream fileStream = null;
		try {
			fileStream = new FileInputStream(file);

			byte [] buf = new byte [11000];

			int bytesRead = fileStream.read(buf);
			if (bytesRead > 10000) {
				System.err.println("Skipping file because it is too large: " + file.getName());
				return;
			}

			if (bytesRead < 10) {
				System.err.println("Skipping file because it is too small: " + file.getName());
				return;
			}

			fileString = new String(buf, 0, bytesRead);

		} catch (IOException exc) {
			System.err.println("Skipping file due to IOException: " + file.getName());
			exc.printStackTrace(System.err);
			return;
		} finally {
			try {
				if (fileStream != null) fileStream.close();
			} catch (IOException exc) {}
		}

		if (fileString == null) return;

		// tokenize by return characters
		StringTokenizer tokenizer = new StringTokenizer(fileString, "\n");
		ArrayList<String> fileLines = new ArrayList<String>();
		while (tokenizer.hasMoreTokens()) {
			fileLines.add(tokenizer.nextToken());
		}

		if (fileLines.size() == 0) {
			System.err.println("Skipping file because it has no lines: " + file.getName());
			return;      
		}

		// check header
		String header = fileLines.get(0);
		if (!header.equals("#POLY SPEED DATE RESULTS FILE")) {
			System.err.println("Skipping file because it does not start with proper header line: " + file.getName());
			return;            
		}
		fileLines.remove(0);

		// check group vs. indiv
		boolean indiv = true;
		//boolean has_ID = false;
	/*	while (fileLines.size() > 0) {
			String tail = (String) fileLines.get(fileLines.size() - 1);

			fileLines.remove(fileLines.size() - 1);

			if (tail == null || tail.trim().length() == 0)        
				continue;

			if ( tail.startsWith( "Current ID" ) || tail.startsWith( "ID:" ) ) {
				has_ID = true;
				continue;
			}
			
			if (tail.trim().equals("Submit_Indiv: Submit_Indiv")) {
				indiv = true;
				break;
			}

			if (tail.trim().equals("Submit_Group: Submit_Group")) {
				indiv = false;
				break;
			}

			System.err.println("Skipping file because it does not end with group or individual tail line: " + file.getName());
			return;
		}
*/
		RegRecord rec = parseFileBody(fileLines, file.getName(), !indiv);
	//	if ( rec != null && !has_ID ) {
	//		appendID( file, rec );
	//	}
	}
	
	
	RegRecord parseFileBody(ArrayList<String> fileLines, String fileName, boolean isGroup ) {

		RegRecord reg = new RegRecord(isGroup);
		reg.buildTmpID( fileName );
		
		for (int i = 0; i < fileLines.size(); i++) {
			String fileLine = fileLines.get(i);

			int indexOfColon = fileLine.indexOf(": ");
			if (indexOfColon < 0) {
				printLineErr(fileLine, fileName);
				continue;
			}

			String left = fileLine.substring(0, indexOfColon);
			String right = fileLine.substring(indexOfColon + 2);

			// we may have multiple lines for friends
			if (left.equals("friends")) {
				int offset = 0;
				while (fileLines.size() > i + offset + 1) {
					String next = fileLines.get(i + offset + 1);
					if (next.indexOf(": ") < 0) {
						right += " " + next;
						offset++;
					} else
						break;
				}
				i += offset;
			}

			parseLine( reg, fileLine, fileName, left, right );

		}  

		reg.cleanUp();



	

			if ( reg.hasName() ) {
				if ( !reg.hasID() ) {
					reg.buildID( fileName, filename_id_flag );
				}
				folks.add( reg );

				//System.out.println( reg.id() + " is " + reg.geekCode() + "\n" );
				return reg;
			} else {
				System.err.println("Warning: seeming empty file file " + fileName);    

			}
		
		return null;
	}
	
	

	private void parseLine(RegRecord reg, String fileLine, String fileName, String left, String right) {

		int pos = 0;
		if ( left.matches( ".*\\d$") ) {
			pos = Integer.parseInt( left.substring( left.length() - 1 ) ) - 1;
			left = left.substring( 0, left.length() - 1 );
		}
		
		//skip empty lines
		if ( right.trim().equals( "" ) ) {
			return;
		}
		
		if ( left.equals( "Time Stamp" ) ) {
			reg.setTimeStamp( Integer.parseInt(right) );
		}
		if (left.equals("first")) {
			reg.setFirst( right, pos );
		} else if (left.equals("last")) {
			reg.setLast( right, pos );
		} else if (left.equals("pubname")) {
			reg.setPubname(right.toLowerCase());
		} else if (left.equals("email")) {
			reg.email = right;
		} else if (left.equals("add_to_list")) {
			Boolean val = parseBoolean(right);
			if (val == null)
				printLineErr(fileLine, fileName);
			else
				reg.add_to_list = val.booleanValue();
		} else if (left.equals("man")) {
			if (!right.equals("isMan"))
				printLineErr(fileLine, fileName);
			else
				reg.setMan( true, pos );
		} else if (left.equals("woman")) {
			if (!right.equals("isWoman"))
				printLineErr(fileLine, fileName);
			else
				reg.setWoman( true, pos );
		} else if (left.equals("genderqueer")) {
			if (!right.equals("isGQ"))
				printLineErr(fileLine, fileName);
			else
				reg.setGQ( true, pos  );
		} else if ( left.equals("transM")) {
			reg.setTransM( true, pos );
		} else if ( left.equals("transW")) {
			reg.setTransW( true, pos );
		} else if ( left.equals("stationary" ) ) {
			reg.stationary = true;
		}
		/*else if ( left.equals( "womanActive" ) ) {
			System.out.println( reg.id() + reg.pubname + "=wa="+right );
			//         reg.womanActive = parseTriple(right);

			//       System.out.println( "reg.wa="+reg.womanActive + "/" + reg.womanActive() );
		} else if ( left.equals( "manActive" ) ) {
			//     reg.manActive = parseTriple(right);
		} */
		else if (left.equals("age")) {
			Integer val = parseNum(right.trim());
			if (val == null)
				printLineErr(fileLine, fileName);
			else
				reg.setAge( val.intValue(), pos );
		} else if (left.equals("lookGenM")) {
			if (!right.equals("wantM"))
				printLineErr(fileLine, fileName);
			else
				reg.setLookM( true, pos );
		} else if (left.equals("lookGenF")) {
			if (!right.equals("wantF"))
				printLineErr(fileLine, fileName);
			else
				reg.setLookW(true, pos );
		} else if (left.equals("lookGenGQ")) {
			if (!right.equals("wantGQ"))
				printLineErr(fileLine, fileName);
			else
				reg.setLookGQ(true, pos );
		} else if ( left.equals("lookGenTransM" ) ) {
			reg.setLookTransM(true,pos);
		} else if ( left.equals("lookGenTransF" ) || left.equals("lookGenTransW" ) ) {
			reg.setLookTransW(true,pos);
		} else if (left.equals("lookNone")) {
			if (!right.equals("wantNone"))
				printLineErr(fileLine, fileName);
			else
				reg.setLookNone(true, pos );
		} else if (left.equals("minAge")) {
			Integer val = parseNum(right);
			if (val == null)
				printLineErr(fileLine, fileName);
			else
				reg.setMinAge( val.intValue(), pos );
		} else if (left.equals("maxAge")) {
			Integer val = parseNum(right);
			if (val == null)
				printLineErr(fileLine, fileName);
			else
				reg.setMaxAge( val.intValue(), pos );
		} else if (left.equals("lookGroup")) {
			if (!right.equals("only") && !right.equals("yes") && !right.equals("no") && !right.equals("yesAll") && !right.equals("yesAny") )
				printLineErr(fileLine, fileName);
			else
				reg.setLookGroup( right );
		} else if (left.equals("referred_by")) {
			reg.setReferred( right.replaceAll( "\\W", " " ));
		} else if (left.equals("friends")) {
			reg.friends = right; // right.replaceAll("[^\\w ]", ".");
		} else if (left.equals("remarks")) {
			reg.setComments( right ); //right.replaceAll("[^\\w ]", ".");
		} else if ( left.startsWith("groupMatch" ) ) {
			reg.setGroupStyle( right );
		} else if ( left.startsWith( "friendship" ) ) {
			reg.setFriendship( right.equals("yes") );
		} else if ( left.startsWith( "ID" ) && !left.startsWith("idCode") ) {
			reg.setID( right.trim() );
		} else if ( left.startsWith( "idCode") ) {
			reg.setIDCode( right.replaceAll("[^\\w ]", ".") );
		} else if ( left.startsWith( "kinky" ) ) {
			reg.setKinky( right.startsWith( "isKinky" ), pos );
		} else if ( left.startsWith( "lookKinky" ) ) {
			reg.setLookKinky( right.trim(), pos );
		} else if ( left.startsWith( "noPrimary" ) ) {
			reg.setPrimary( true, pos );
		} else if ( left.startsWith( "want_childcare")) {
			reg.setNeedChildcare( WU.parseYesNo(right) );
		} else if ( left.startsWith( "childcare_details")) {
			reg.setChildcareDetails( right );
		} else if (left.startsWith("location")) {
			if (right.equals("fromEB"))
				reg.fromEB = true;
			else if (right.equals("fromSB"))
				reg.fromSB = true;
			else if (right.equals("fromNB"))
				reg.fromNB = true;
			else if (right.equals("fromSF"))
				reg.fromSF = true;
			else if (right.equals("fromPN"))
				reg.fromPN = true;
			else if (right.equals("fromSE"))
				reg.fromSE = true;
			else printLineErr(fileLine, fileName);
		} else if ( left.startsWith("Notes") || left.startsWith("notes")) {
			reg.setNotes( right );
		}
		else if ( left.startsWith( "Coming" ) || left.startsWith("coming") ) {
			reg.setComing( WU.parseYesNo(right) );
		}
		else if (left.startsWith( "Submit" ) ) {
			if ( right.contains( "Indiv" ) ) {
				reg.setGroup( false );
			} else {
				reg.setGroup( true );
			}
		}
		
		
	}
	
	
	Integer parseNum(String numString) {
		try {
			int num = Integer.valueOf(numString);
			return Integer.valueOf(num);
		} catch (NumberFormatException exc) {
			return null;
		}
	}

	int parseTriple( String trip ) {
		System.out.println( "parseTrip="+trip+".");
		if ( trip.equalsIgnoreCase("yes" ) ) {
			return Matcher.YES;
		} else if ( trip.equalsIgnoreCase( "no" ) ) {
			return Matcher.NO;
		} else {
			return Matcher.UNKNOWN;
		}
	}

	void printLineErr(String line, String file) {
		System.err.println("Warning: unable to parse line '" + line + "' in file " + file);    
	}

	private void printUsage() {
		System.err.println("usage: java RegParser [-output <output file>] [-no_comments] [-file_name_ids]" +
		"[-matrix <output file>] <file-or-directories>");
	}

	

	String yesBlank(boolean val) {
		return (val) ? "yes" : "";
	}



	String yesNo(boolean val) {
		return (val) ? "yes" : "no";
	}

	
	String yesNoBlank(int val) {
		switch ( val ) {
		case Matcher.YES: return "yes";
		case Matcher.NO: return "no";
		case Matcher.UNKNOWN: return "";
		default: throw new RuntimeException( "Illegal value for yesNoBlank: " + val );
		}
	}
	
}

